/**
 * Utils 帮助使用 Promise 对象。
 */
export class PromiseUtils {

  /**
   * 创建一个新的 promise 使用 Promise.resolved 用于 lazy relations.
   */
  public static create(value: any) {
    const promise = Promise.resolve(value);
    (promise as any).__value__ = value
    return promise
  }

  /**
   * 如果被给的 value 是通过 create 方法来创建的， 那么通过这个方法可以获取 value
   * 如果给是值不是 promise 那么被给的值将会被放回
   */
  public static extractValue(object: any) {
    if (object instanceof Promise && (object as any).__value__) {
      return (object as any).__value__
    }

    return object
  }

  /**
   * 运行给定的 callback，按顺序返回给定集合中每个 item 的 promise。
   * 在之前的 Promise 得到 resolve 之后，彼此之后执行的操作。
   */
  public static runInSequence<T, U>(collection: T[], callback: (item: T) => Promise<U>): Promise<U[]> {
    const results: U[] = []
    return collection.reduce((promise, item) => {
      return promise.then(() => {
        return callback(item)
      }).then((result) => {
        results.push(result)
      })
    }, Promise.resolve()).then(() => {
      return results
    })
  }

  /**
   * 返回使用 promise 数据 快照数组 实现的 promise，
   * 但只有在所有的 promise 已经解决之后，即成为 resolve 或 reject。
   */
  public static settle(promises: Array<Promise<any>>) {
    return Promise.all(promises.map((p) => Promise.resolve(p).then((v) => ({
      state: 'fulfilled',
      value: v,
    }), (r) => ({
      state: 'rejected',
      reason: r,
    })))).then((results: any[]): any => {
      const rejected = results.find((result) => result.state === 'rejected')
      if (rejected) {
        return Promise.reject(rejected.reason)
      }

      return results.map((result) => result.value)
    })
  }

}
